package persistence.product;

import java.sql.*;
import java.util.Iterator;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import model.Product;

public class ProductDAOJDBC implements ProductDAO {

    private final Object lockOfTheConexion = new Object();
    private Connection conexion = null;
    private static ProductDAOJDBC persistenceManager = null;
    private static final Logger logger = Logger.getLogger(ProductDAOJDBC.class.getName());

    ProductDAOJDBC() {
    }

    public static ProductDAOJDBC getJDBCPersistenceManager() {
        if (persistenceManager == null) {
            persistenceManager = new ProductDAOJDBC();
        }
        return persistenceManager;
    }

    @Override
    public boolean setUp(String url, String driver, String user, String password) {
        try {
            Class.forName(driver);
            conexion = DriverManager.getConnection(url, user, password);
        } catch (ClassNotFoundException ex) {
            logger.log(Level.SEVERE, "No se encontro el driver para la base de datos", ex);
            return false;
        } catch (SQLException ex) {
            logger.log(Level.SEVERE, "No se pudo establecer la conexion con la base de datos", ex);
            return false;
        }
        setUpMap();
        return true;
    }

    @Override
    public void setUpMap() {
        String query = null;
        query = "select * from \"PRODUCTOS\"";
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        Product product = new Product();
        try {
            synchronized (lockOfTheConexion) {
                statement = conexion.prepareStatement(query);
            }
            resultSet = statement.executeQuery();
            for (int i = 0; resultSet.next(); i++) {
                product = new Product();
                product.setId(resultSet.getString("ID"));
                product.setNombre(resultSet.getString("NOMBRE"));
                product.setPrecio(resultSet.getFloat("PRECIO"));
                product.setDescripcionc(resultSet.getString("DESCRIPCIONC"));
                product.setDescripcionl(resultSet.getString("DESCRIPCIONL"));
                product.setSo(resultSet.getString("SO"));
                product.setVentas(resultSet.getInt("VENTAS"));
                product.setFecha(resultSet.getString("FECHA"));
                product.setUsuario(resultSet.getString("USUARIO"));
                productMap.put(product.getId(), product);
            }
        } catch (SQLException ex) {
            logger.log(Level.SEVERE, "Error al recuperar un producto", ex);
            product = null;

        } finally {
            if (resultSet != null) {
                try {
                    resultSet.close();
                    statement.close();
                } catch (SQLException ex) {
                    logger.log(Level.SEVERE, "Error al cerrar la conexon a la base de datos", ex);
                }
            }
        }
    }

    @Override
    public boolean disconnect() {
        try {
            conexion.close();
        } catch (SQLException ex) {
            logger.log(Level.SEVERE, "Conexi�n a la base de datos no cerrada", ex);
            return false;
        }
        return true;
    }

    @Override
    public boolean createProduct(Product product) {
        String query = "insert into\"PRODUCTOS\" values(?,?,?,?,?,?,?,?,?)";
        PreparedStatement statement;
        String id = product.getNombre() + "_" + product.getSo();
        if (productMap.containsKey(id)){
            return false;
        } else {    
            try {
                synchronized (lockOfTheConexion) {
                    statement = conexion.prepareStatement(query);
                }
                product.setId(product.getNombre() + "_" + product.getSo());
                statement.setString(1, product.getId());
                statement.setString(2, product.getNombre());
                statement.setFloat(3, product.getPrecio());
                statement.setString(4, product.getDescripcionc());
                statement.setString(5, product.getDescripcionl());
                statement.setString(6, product.getSo());
                statement.setInt(7, product.getVentas());
                statement.setString(8, product.getFecha());
                statement.setString(9, product.getUsuario());
                statement.execute();
                productMap.put(product.getId(), product);
                return true;
            } catch (SQLException ex) {
                logger.log(Level.SEVERE, "Error al crear un producto", ex);
                return false;
            }
        }
    }

    @Override
    public boolean deleteProduct(String name) {
        String query = "delete from \"PRODUCTOS\" where ID = ?";
        PreparedStatement statement;
        try {
            synchronized (lockOfTheConexion) {
                statement = conexion.prepareStatement(query);
            }
            statement.setString(1, name);
            statement.execute();
            productMap.remove(name);
            return true;
        } catch (SQLException ex) {
            logger.log(Level.SEVERE, "Error al borrar un producto", ex);
            return false;
        }
    }

    @Override
    public boolean updateProduct(String name, Product product) {
        String query = null;
        query = "update \"PRODUCTOS\" SET ID = ?,NOMBRE = ?,PRECIO = ?,DESCRIPCIONC = ?,DESCRIPCIONL = ?,"
                + " VENTAS = ?, SO = ?, FECHA = ?, USUARIO = ? where ID = ?";
        PreparedStatement statement;
        String id = product.getNombre() + "_" + product.getSo();
        if ( !name.equals(id) && productMap.containsKey(id)){
            return false;
        } else {
            try {
                synchronized (lockOfTheConexion) {
                    statement = conexion.prepareStatement(query);
                }
                product.setId(product.getNombre() + "_" + product.getSo());
                statement.setString(1, product.getId());
                statement.setString(2, product.getNombre());
                statement.setFloat(3, product.getPrecio());
                statement.setString(4, product.getDescripcionc());
                statement.setString(5, product.getDescripcionl());
                statement.setInt(6, product.getVentas());
                statement.setString(7, product.getSo());
                statement.setString(8, product.getFecha());
                statement.setString(9, product.getUsuario());
                statement.setString(10, name);
                statement.execute();
                productMap.remove(name);
                productMap.put(product.getId(), product);
                return true;
            } catch (SQLException ex) {
                logger.log(Level.SEVERE, "Error al actualizar un producto", ex);
                return false;
            }
        }
    }

    @Override
    public synchronized void readProduct(String name, Map<String, Product> productArray) {
        Product product = productMap.get(name);
        if (product != null) {
            productArray.put(product.getId(), product);
            return;
        }
        product = productMap.get(name + "_iOS");
        if (product != null) {
            productArray.put(product.getId(), product);
        }
        product = productMap.get(name + "_Android");
        if (product != null) {
            productArray.put(product.getId(), product);
        }
        product = productMap.get(name + "_Blackberry");
        if (product != null) {
            productArray.put(product.getId(), product);
        }
        product = productMap.get(name + "_Windows Phone");
        if (product != null) {
            productArray.put(product.getId(), product);
        }
    }

    @Override
    public synchronized void readAllProducts(Map<Integer, Product> productArray, String so) {
        Iterator itr = productMap.entrySet().iterator();
        if (so == null) {
            for (int i = 1; itr.hasNext(); i++) {
                Map.Entry e = (Map.Entry) itr.next();
                productArray.put(i, (Product) e.getValue());
            }
        } else {
            String s;
            for (int i = 1; itr.hasNext();) {
                Map.Entry e = (Map.Entry) itr.next();
                s = (String) e.getKey();
                if (s.contains(so)) {
                    productArray.put(i, (Product) e.getValue());
                    i++;
                }
            }
        }
    }

    public void setConnection(Connection conexion) {
        synchronized (lockOfTheConexion) {
            this.conexion = conexion;
        }
    }

    @Override
    public synchronized int readPageProducts(Map<Integer, Product> productArray, String so, int pagina) {
        Iterator itr = productMap.entrySet().iterator();
        if (so == null) {
            for (int i = 1; i < (pagina*2)-1 && itr.hasNext(); i++){
                itr.next();
            }
            for (int i = 1; i < 3 &&itr.hasNext(); i++) {
                Map.Entry e = (Map.Entry) itr.next();
                productArray.put(i, (Product) e.getValue());
            }
        } else {
            String s;
            for (int i = 1; i < (pagina*2)-1 && itr.hasNext(); ){
                s = (String) ((Map.Entry) itr.next()).getKey();
                if (s.contains(so))
                    i++;
            }
            for (int i = 1; i < 3 && itr.hasNext(); ) {
                Map.Entry e = (Map.Entry) itr.next();
                s = (String) e.getKey();
                if (s.contains(so)) {
                    productArray.put(i, (Product) e.getValue());
                    i++;
                }
            }
        }
        return productMap.size();
    }
}
